/* Copyright (c) 2024 Qualcomm Technologies International, Ltd. */
/* %%version */

#include "gatt_ots_client_indication.h"
#include "gatt_ots_client_select_object.h"
#include "gatt_ots_client_read_object.h"

static void otscSendRegIndicationInd(GOTSC *const gattOtsClient,
                              GattOtscCharacteristicsId characId,
                              GattOtscResultCode result,
                              CsrBtSupplier supplier)

{
    GattOtscRegisterForIndicationInd *message = CsrPmemAlloc(sizeof(*message));

    /* Fill in client reference */
    message->svcHandle  = gattOtsClient->srvcElem->service_handle;
    message->characId   = characId;
    message->resultCode = result;
    message->supplier   = supplier;

    GATT_OTS_CLIENT_INFO("GOTSC : otscSendRegIndicationInd: svcHandle(0x%02x)\n", gattOtsClient->srvcElem->service_handle);

    /* Send the confirmation message to app task  */
    GattOtscMessageSend(gattOtsClient->appTask,
                        GATT_OTSC_REGISTER_FOR_INDICATION_IND, 
                        message);
}

static void otscSendRegIndicationCfm(GOTSC *const gattOtsClient,
                                     GattOtscCharacteristicsId characId,
                                     GattOtscResultCode result,
                                     CsrBtSupplier supplier)
{
    GattOtscRegisterForIndicationCfm *message = CsrPmemAlloc(sizeof(*message));

    message->svcHandle  = gattOtsClient->srvcElem->service_handle;
    message->characId   = characId;
    message->resultCode = result;
    message->supplier   = supplier;

    gattOtsClient->pendingCmd &= ~OTSC_PENDING_OP_WRITE_OTHER_CCCD;

    GATT_OTS_CLIENT_INFO("GOTSC : otscSendRegIndicationCfm: svcHandle(0x%02x)\n", gattOtsClient->srvcElem->service_handle);

    /* Send the confirmation message to app task  */
    GattOtscMessageSend(gattOtsClient->appTask,
                        GATT_OTSC_REGISTER_FOR_INDICATION_CFM,
                        message);
}

static void otscSendObjectChangedInd(GOTSC *const gattOtsClient,
                                     const CsrBtGattClientIndicationInd *ind)
{
    GattOtscObjectChangedInd *message = CsrPmemZalloc(sizeof(*message));
    uint8 mask = 0x01;
    uint8 objChangedFlag = ind->value[0];

    message->svcHandle = gattOtsClient->srvcElem->service_handle;
    message->modifier  = GATT_OTSC_DEVICE_ROLE_SERVER;
    memcpy(&message->objectId, &ind->value[1], sizeof(GattOtscObjectId));

    while (objChangedFlag)
    {
        switch (objChangedFlag & mask)
        {
            case OTSC_OBJ_CHANGE_SOURCE:
            {
                message->modifier     = GATT_OTSC_DEVICE_ROLE_CLIENT;
                break;
            }
            case OTSC_OBJ_CONTENT_CHANGED:
            {
                message->modification = GATT_OTSC_OBJ_CONTENT_CHANGED;
                break;
            }
            case OTSC_OBJ_METADATA_CHANGED:
            {
                message->modification |= GATT_OTSC_OBJ_METADATA_CHANGED;
                break;
            }
            case OTSC_OBJ_CREATED:
            {
                message->modification = GATT_OTSC_OBJ_CREATED;
                break;
            }
            case OTSC_OBJ_DELETED:
            {
                message->modification = GATT_OTSC_OBJ_DELETED;
                break;
            }
            default:
            {
                break;
            }
        }

        objChangedFlag &= ~mask;
        mask <<= 1;
    }

    GATT_OTS_CLIENT_INFO("GOTSC : otscSendObjectChangedInd: svcHandle(0x%02x)\n", gattOtsClient->srvcElem->service_handle);

    GattOtscMessageSend(gattOtsClient->appTask,
                        GATT_OTSC_OBJECT_CHANGED_IND,
                        message);
}

void OtscHandleClientIndication(GOTSC *const gattOtsClient, const CsrBtGattClientIndicationInd *ind)
{
    /* Send the Indication response */
    CsrBtGattClientIndicationRspSend(gattOtsClient->srvcElem->gattId, gattOtsClient->srvcElem->cid);

    if (ind->valueHandle == gattOtsClient->deviceData.objChangedHandle)
    {
        otscSendObjectChangedInd(gattOtsClient, ind);
    }
    else if (ind->valueHandle == gattOtsClient->deviceData.objActionControlPointHandle)
    {
        /* handle OACP control point ind */
        OtscHandleObjActionControlPointInd(gattOtsClient, ind);
    }
    else if (ind->valueHandle == gattOtsClient->deviceData.objListControlPointHandle)
    {
        /* handle OLCP control point ind */
        OtscHandleObjListControlPointInd(gattOtsClient, ind);
    }
    else
    {
        /* Never likely to come */
    }
}

void GattOtscRegisterForIndicationReq(ServiceHandle svcHandle, GattOtscCharacValuesMask valMask)
{
    GOTSC *gattOtsClient = ServiceHandleGetInstanceData(svcHandle);

    GATT_OTS_CLIENT_INFO("GOTSC : GattOtscRegisterForIndicationReq: svcHandle(0x%02x)\n", svcHandle);

    if (gattOtsClient)
    {
        OtscInternalMsgRegIndication *message = CsrPmemAlloc(sizeof(*message));

        message->svcHandle    = gattOtsClient->srvcElem->service_handle;
        message->charsValMask = valMask;

        gattOtsClient->pendingCmd |= OTSC_PENDING_OP_WRITE_OTHER_CCCD;

        GattOtscMessageSend(gattOtsClient->libTask,
                            OTSC_INTERNAL_MSG_REG_INDICATION_REQ,
                            message);
    }
    else
    {
        GATT_OTS_CLIENT_ERROR("GOTSC: Invalid OTS Client instance!\n");
    }
}

void OtscHandleInternalMsgRegisterForIndication(GOTSC *gattOtsClient, OtscInternalMsgRegIndication* msg)
{
    uint16 mask = 0x0001;
    GattOtscCharacValuesMask charsValMask = msg->charsValMask;

    /* Reset the write CCC count value beforehand */
    gattOtsClient->writeCccCount = 0;

    while (charsValMask)
    {
        uint16 currHandle = GATT_ATTR_HANDLE_INVALID;
        uint8  val        = 0;

        switch (charsValMask & mask)
        { /* Retrieve the characteristic handle for which indication request is received */
            case GATT_OTSC_ENABLE_OBJ_CHANGED_IND:
            {
                currHandle = gattOtsClient->deviceData.objChangedCCCDHandle;
                val        = OTS_INDICATION_VALUE;
            }
            break;

            case GATT_OTSC_DISABLE_OBJ_CHANGED_IND:
            {
                currHandle = gattOtsClient->deviceData.objChangedCCCDHandle;
            }
            break;

            default:
            {
                GATT_OTS_CLIENT_ERROR("GOTSC: Invalid OTS Characteristic !\n");
            }
            break;
        }

        charsValMask &= ~mask;
        mask <<= 1;

        if (currHandle != GATT_ATTR_HANDLE_INVALID)
        {
            uint8* value = (uint8*)(CsrPmemZalloc(GATT_OTS_CLIENT_CHARACTERISTIC_CONFIG_SIZE));
            value[0]     = val;

            /* Increment readCount to track total write requests made to GATT */
            gattOtsClient->writeCccCount++;

            CsrBtGattWriteReqSend(gattOtsClient->srvcElem->gattId,
                                  gattOtsClient->srvcElem->cid,
                                  currHandle,
                                  0,
                                  GATT_OTS_CLIENT_CHARACTERISTIC_CONFIG_SIZE,
                                  value);
        }
    }
}

void OtscHandleWriteCfmToRegisterInd(GOTSC *const gattOtsClient,
                                     const CsrBtGattWriteCfm *cfm)
{
    GattOtscResultCode result          = cfm->resultCode == CSR_BT_GATT_RESULT_SUCCESS ? GATT_OTSC_RESULT_CODE_SUCCESS : cfm->resultCode;
    CsrBtSupplier supplier             = cfm->resultCode == CSR_BT_GATT_RESULT_SUCCESS ? GATT_SUPPLIER_OTS_CLIENT : cfm->resultSupplier;
    GattOtscCharacteristicsId characId = cfm->handle == gattOtsClient->deviceData.objChangedCCCDHandle ? GATT_OTSC_CHARAC_ID_OBJ_CHANGED : GATT_OTSC_CHARAC_ID_NONE;

    gattOtsClient->writeCccCount--;

    if (gattOtsClient->writeCccCount != 0)
    {
        otscSendRegIndicationInd(gattOtsClient, characId, result, supplier);
    }
    else
    {
        otscSendRegIndicationCfm(gattOtsClient, characId, result, supplier);
    }
}

